"""
$Id: main.py 2 2007-03-04 19:08:44Z sidnei.da.silva $
"""

import os
import re
import sys
import glob
import logging
from optparse import OptionParser
from voting import central, zone, section, simul, ui, graph, constants

ZONE_ID_RE = re.compile('.*zone-(?P<ZONE_ID>.*).dat$')

if __name__ == '__main__':
    parser = OptionParser()
    parser.add_option("", "--simulate",
                      action="store_true",
                      help="Simulate")
    parser.add_option("", "--ui",
                      action="store_true",
                      help="Use graphical UI")
    parser.add_option("", "--plot",
                      action="store_true",
                      help="Plot status graph")
    parser.add_option("-c", "--central",
                      action="store_true",
                      help="Run Central")
    parser.add_option("-w", "--wait",
                      action="store_true",
                      help="Wait for a keypress")
    parser.add_option("-l", "--log-file",
                      action="store",
                      metavar="<LOG_FILE>",
                      help="Log file")
    parser.add_option("-d", "--data-dir",
                      action="store",
                      metavar="<DATA_DIR>",
                      help="Host for Central")
    parser.add_option("-H", "--host",
                      action="store",
                      metavar="<HOST>",
                      default='127.0.0.1',
                      help="Host for Central")
    parser.add_option("-p", "--port",
                      action="store",
                      type='int',
                      metavar="<PORT>",
                      default=constants.DEFAULT_PORT,
                      help="Port for Central")

    options, args = parser.parse_args()

    if options.log_file:
        logging.basicConfig(level=logging.INFO, filename=options.log_file)
    else:
        logging.basicConfig(level=logging.DEBUG)

    data_dir = options.data_dir
    if not data_dir:
        here = os.path.dirname(os.path.abspath(sys.argv[0]))
        data_dir = os.path.join(here, 'data')

    if not os.path.exists(data_dir) or not os.path.isdir(data_dir):
        parser.error('<DATA_DIR> must be a valid directory')

    if not (options.central or options.ui or options.simulate):
        parser.error('Must use one of --central, --ui '
                     'or --simulate')

    address = (options.host, options.port)

    # Read zone data
    zone_data = {}
    for fname in glob.glob(os.path.join(data_dir, 'zone-*.dat')):
        zone_id = int(ZONE_ID_RE.match(fname).groupdict()['ZONE_ID'])
        data = []
        f = open(fname, 'rb')
        try:
            for line in f:
                line = line.strip()
                if line:
                    data.append(line)
        finally:
            zone_data[zone_id] = tuple(data)
            f.close()

    if options.central:
        # Initialize 1 Central
        c = central.Central(zone_data, address=address,
                            backlog=len(zone_data.keys()))
        c.start()

        if options.plot:
            g = graph.Graph(c.cond, c.votes)
            g.start()

    if options.simulate or options.ui:
        # Initialize N Zones
        zones = []
        sections = {}
        for zone_id in zone_data.keys():
            z = zone.Zone(zone_id, zone_data[zone_id], address=address)
            z.start()
            zones.append(z)
            sections[zone_id] = sect = []
            # For each zone initialize 2 sections.
            for section_id in range(0, 2):
                sect.append((section_id, section.Section(section_id, z)))

        if options.simulate:
            term_factory = simul.Simulator
        elif options.ui:
            term_factory = ui.UI
        else:
            raise ValueError('No valid terminal class informed')

        terminals = []
        for zone_id, data in zone_data.items():
            terminals.append(term_factory(zone_id, sections[zone_id], data))

        for t in terminals:
            t.start()

    if options.wait:
        raw_input('Press a key to exit...')

        if options.simulate or options.ui:
            for t in terminals:
                t.stop()

            for z in zones:
                z.stop()

        if options.central:
            c.stop()

            if options.plot:
                g.stop()

    if options.simulate or options.ui:
        for t in terminals:
            t.join()

        for z in zones:
            z.join()
